import * as React from 'react';
import { connect } from 'react-redux';

import './AudioPlayer.scss';

const SECOND = 60;
const PROGRESS_WIDTH = 105;

interface AudioPlayerProps {
  audioUri: string;
  isTiny: boolean;
}

interface AudioPlayerState {
  isPlaying: boolean;
  strokeDashOffset: number;
  minus: number;
  second: number;
}

class AudioPlayer extends React.PureComponent<AudioPlayerProps, AudioPlayerState> {
  audioPlayer: any;
  static inPlaySource: any;
  static defaultProps: AudioPlayerProps = {
    audioUri: '',
    isTiny: true,
  };
  constructor(props: AudioPlayerProps) {
    super(props);

    this.state = {
      isPlaying: false,
      strokeDashOffset: PROGRESS_WIDTH,
      minus: 0,
      second: 0,
    };
  }

  componentWillUnmount() {
    this.audioPlayer = null;
    AudioPlayer.inPlaySource = null;
  }

  handleEnded = () => {
    this.setState({
      isPlaying: false,
    });
    AudioPlayer.inPlaySource = null;
  };

  handleAudioPlay = () => {
    if (this.audioPlayer === null) {
      return;
    }

    if (this.audioPlayer.paused) {
      if (
        AudioPlayer.inPlaySource &&
        (!AudioPlayer.inPlaySource.audioPlay || !AudioPlayer.inPlaySource.audioPlayer.paused)
      ) {
        AudioPlayer.inPlaySource.handleAudioPlay();
      }
      AudioPlayer.inPlaySource = this;
      this.audioPlayer.play();
    } else {
      AudioPlayer.inPlaySource = null;
      this.audioPlayer.pause();
    }

    this.setState({
      isPlaying: !this.audioPlayer.paused,
    });
  };

  handleTimeUpdate = (e: any) => {
    const player = e.currentTarget;

    this.setState({
      strokeDashOffset:
        PROGRESS_WIDTH - Math.round((player.currentTime / player.duration) * PROGRESS_WIDTH),
    });
  };

  handleLoadedMetadata = (e: any) => {
    const player = e.currentTarget;

    this.setState({
      minus: Math.floor(player.duration / SECOND),
      second: Math.floor(player.duration % SECOND),
    });
  };

  render() {
    const { audioUri, isTiny } = this.props;
    const { isPlaying, minus, second, strokeDashOffset } = this.state;

    const pauseComponent = (
      <g>
        <rect
          fill="#FFFFFF"
          x="23.1400651"
          y="22.656"
          width="3.12703583"
          height="12.5866667"
          rx="1.56351792"
        />
        <rect
          fill="#FFFFFF"
          x="30.019544"
          y="22.656"
          width="3.12703583"
          height="12.5866667"
          rx="1.56351792"
        />
      </g>
    );
    const playingComponent = (
      <polygon
        id="Triangle"
        fill="#FFFFFF"
        transform="translate(30.500000, 29.000000) scale(-1, 1) rotate(270.000000) translate(-30.500000, -29.000000) "
        points="30.5 23.5 37.5 34.5 23.5 34.5"
      />
    );
    const statusComponent = isPlaying ? pauseComponent : playingComponent;

    if (!audioUri) {
      return null;
    }

    if (isTiny) {
      return (
        <div style={{ textAlign: 'center' }}>
          <audio
            preload="meta"
            src={audioUri}
            ref={input => {
              this.audioPlayer = input;
            }}
            onEnded={this.handleEnded}
          />
          <svg style={{ verticalAlign: 'middle' }} width="65px" height="65px" viewBox="0 0 65 65">
            <g fill="white" transform="translate(4.000000, 4.000000)">
              <rect
                id="path-1"
                stroke="#C8EBFC"
                strokeWidth="3"
                x="0"
                y="0"
                width="56.64"
                height="56.64"
                rx="28.32"
              />
              <g
                onClick={e => {
                  e.stopPropagation();
                  this.handleAudioPlay();
                }}>
                <ellipse
                  id="Oval"
                  fill="#2BB1F3"
                  cx="29.0814332"
                  cy="28.0053333"
                  rx="22.8273616"
                  ry="22.9706667"
                />
                {statusComponent}
              </g>
            </g>
          </svg>
        </div>
      );
    }

    return (
      <div style={{ padding: 4 }}>
        <audio
          preload="meta"
          src={audioUri}
          ref={input => {
            this.audioPlayer = input;
          }}
          onTimeUpdate={this.handleTimeUpdate}
          onLoadedMetadata={this.handleLoadedMetadata}
          onEnded={this.handleEnded}
        />
        <svg width="200px" height="65px" viewBox="0 0 200 65">
          <g fill="white" transform="translate(4.000000, 4.000000)">
            <rect
              id="path-1"
              stroke="#C8EBFC"
              strokeWidth="3"
              x="0"
              y="0"
              width="192"
              height="56.64"
              rx="28.32"
            />
            <g
              onClick={e => {
                e.stopPropagation();
                this.handleAudioPlay();
              }}>
              <ellipse
                id="Oval"
                fill="#2BB1F3"
                cx="29.0814332"
                cy="28.0053333"
                rx="22.8273616"
                ry="22.9706667"
              />
              {statusComponent}
            </g>
            <line
              x1="61"
              y1="41"
              x2="166"
              y2="41"
              strokeLinecap="round"
              strokeWidth="3"
              stroke="#D8D8D8"
            />
            <line
              x1="61"
              y1="41"
              x2="166"
              y2="41"
              strokeLinecap="round"
              strokeDasharray="105"
              strokeDashoffset={strokeDashOffset}
              strokeWidth="3"
              stroke="#2BB1F3"
            />
            <text fill="#656565">
              <tspan x="60" y="28">
                {minus}′{second}″
              </tspan>
            </text>
          </g>
        </svg>
      </div>
    );
  }
}

interface OwnProps {
  audioUri: string;
  isTiny: boolean;
}

function mapStateToProps(state: any, ownProps: OwnProps) {
  const { audioUri, isTiny } = ownProps;
  return {
    audioUri,
    isTiny,
  };
}

export default connect(mapStateToProps)(AudioPlayer);
